package org.lee.ast

import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.ast.MethodNode
import org.codehaus.groovy.ast.expr.ArgumentListExpression
import org.codehaus.groovy.ast.expr.ConstantExpression
import org.codehaus.groovy.ast.expr.MethodCallExpression
import org.codehaus.groovy.ast.expr.VariableExpression
import org.codehaus.groovy.ast.stmt.ExpressionStatement
import org.codehaus.groovy.ast.stmt.Statement
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.transform.ASTTransformation
import org.codehaus.groovy.transform.GroovyASTTransformation
import org.lee.ast.ann.WithLogging

@GroovyASTTransformation(phase=CompilePhase.SEMANTIC_ANALYSIS)
class LoggingASTTransformation implements ASTTransformation {

	public void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
		List methods = sourceUnit.getAST()?.getMethods()
//		List methods = sourceUnit.getAST().classes*.methods.flatten()
		
		// find all methods annotated with @WithLogging
		methods.findAll { MethodNode method ->
			method.getAnnotations(new ClassNode(WithLogging))
		}.each { MethodNode method ->
			Statement startMessage = createPrintlnAst("Starting $method.name")
			Statement endMessage = createPrintlnAst("Ending $method.name")

			List existingStatements = method.getCode().getStatements()
			existingStatements.add(0, startMessage)
			existingStatements.add(endMessage)
		}
	}

	private Statement createPrintlnAst(String message) {
		return new ExpressionStatement(
				new MethodCallExpression(
					new VariableExpression("this"),
					new ConstantExpression("println"),
					new ArgumentListExpression(
						new ConstantExpression(message)
				)
			)
		)
	}

}
